package cn.hg.solon.youcan.system.provider;

import cn.hg.solon.youcan.common.exception.ServiceException;
import cn.hg.solon.youcan.common.util.PasswordUtil;
import cn.hg.solon.youcan.easyquery.util.EntityQueryableUtil;
import cn.hg.solon.youcan.system.entity.EqDept;
import cn.hg.solon.youcan.system.entity.EqUser;
import cn.hg.solon.youcan.system.entity.EqUserRoleMapping;
import cn.hg.solon.youcan.system.entity.User;
import cn.hg.solon.youcan.system.entity.proxy.EqUserProxy;
import cn.hg.solon.youcan.system.service.UserService;
import com.easy.query.api.proxy.client.EasyEntityQuery;
import com.easy.query.api.proxy.entity.select.EntityQueryable;
import com.easy.query.core.api.pagination.EasyPageResult;
import com.easy.query.core.basic.api.select.Query;
import com.easy.query.solon.annotation.Db;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.bean.copier.CopyOptions;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.text.StrValidator;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
import org.dromara.hutool.db.Page;
import org.dromara.hutool.db.PageResult;
import org.noear.solon.annotation.Component;
import org.noear.solon.data.annotation.Tran;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 胡高
 */
@Component
public class EqUserProvider implements UserService {

    @Db
    private EasyEntityQuery easyEntityQuery;

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#assignRole(cn.hg.solon.youcan.system.entity.User, java.lang.Integer[])
     */
    @Tran
    @Override
    public void assignRole(User bean, List<Integer> roleIds) {
        /*
         * 删除所有关联角色
         * DELETE FROM sys_user_role WHERE user_id = ${bean.id}
         */
        this.easyEntityQuery.deletable(EqUserRoleMapping.class)
                .where(t -> t.userId().eq(bean.getId()))
                .allowDeleteStatement(true)
                .executeRows();

        /*
         * 重新建立用户角色映射
         */
        List<EqUserRoleMapping> beanList = new ArrayList<>();
        for (int id : roleIds) {
            EqUserRoleMapping urm = new EqUserRoleMapping();
            urm.setUserId(bean.getId());
            urm.setRoleId(id);

            beanList.add(urm);
        }

        if (CollUtil.isNotEmpty(beanList)) {
            this.easyEntityQuery.insertable(beanList).executeRows();
        }
    }

    private EntityQueryable<EqUserProxy, EqUser> buildQuery(Page page, Map<String, Object> map) {
        String word = (String) map.get("word");
        String status = (String) map.get("status");
        Integer deptId = (Integer) map.get("deptId");

        // 部门及所有下级部门ID子查询
        Query<Integer> queryDeptIdList = this.easyEntityQuery
                // FROM sys_dept AS t1
                .queryable(EqDept.class)
                // WHERE t1.`del` = FALSE AND ( FIND_IN_SET({deptId}, t1.`ancestors` ) OR t1.`id` = {deptId} )
                .where(t1 -> t1.or(() -> {
                    t1.expression().sql("FIND_IN_SET({0}, ({1}))", c -> {
                        c.value(deptId);
                        c.expression(t1.ancestors());
                    });
                    t1.id().eq(deptId);
                }))
                // SELECT t1.`id`
                .selectColumn(t -> t.id());

        EntityQueryable<EqUserProxy, EqUser> entityQueryable = this.easyEntityQuery
                // FROM sys_user AS t
                .queryable(EqUser.class)
                // WHERE t.`dept_id` IN (子查询) AND t.`status` = ${status}
                .where(t -> {
                    t.deptId().in(ObjUtil.isNotNull(deptId), queryDeptIdList);
                    t.status().eq(StrValidator.isNotBlank(status), status);
                    //  AND (t.`account` LIKE '%${word}%' OR t.`nickname` LIKE '%${word}%' OR t.`email` LIKE '%${word}%' OR t1.`phone` LIKE '%${word}%')
                    t.or(StrValidator.isNotBlank(word), () -> {
                        t.account().like(word);
                        t.nickname().like(word);
                        t.email().like(word);
                        t.phone().like(word);
                    });
                });

        // ORDER BY ${sortField}
        return EntityQueryableUtil.applyOrderBy(entityQueryable, page);
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#checkUnique(cn.hg.solon.youcan.system.entity.User)
     */
    @Override
    public boolean checkUnique(User bean) {
        return !this.easyEntityQuery
                // FROM sys_user AS t
                .queryable(EqUser.class)
                // WHERE t.`account` = ${bean.account} AND t.`id` <> ${bean.id}
                .where(t -> {
                    t.account().eq(bean.getAccount());
                    t.id().ne(ObjUtil.isNotNull(bean.getId()), bean.getId());
                })
                .any();
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#delete(java.util.List)
     */
    @Override
    public boolean delete(List<Integer> idList) {
        if (CollUtil.contains(idList, Integer.valueOf(1))) {
            throw new ServiceException("初始的 超级管理员 不允许删除！");
        }
        return this.easyEntityQuery.deletable(EqUser.class).where(t -> t.id().in(idList)).executeRows() > 0L;
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#get(java.lang.Integer)
     */
    @Override
    public EqUser get(Integer id) {
        return this.easyEntityQuery.queryable(EqUser.class).whereById(id).firstOrNull();
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#getByAccount(java.lang.String)
     */
    @Override
    public EqUser getByAccount(String account) {
        return this.easyEntityQuery.queryable(EqUser.class).where(t -> t.account().eq(account)).firstOrNull();
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#insert(cn.hg.solon.youcan.system.entity.User, java.util.List)
     */
    @Override
    public boolean insert(User bean, List<Integer> roleIdList) {
        if (!this.checkUnique(bean)) {
            throw new ServiceException("登录账号已经存在，请更换其它值！");
        }

        // 初始化密码
        bean.setSalt(RandomUtil.randomString(20));
        bean.setPassword(PasswordUtil.genSecretPassword(bean.getSalt(), bean.getPassword()));

        EqUser cloneBean = BeanUtil.copyProperties(bean, EqUser.class);

        // 注意：插入时使用的True，代表插入同时获取ID值填充到cloneBean
        boolean ret = this.easyEntityQuery.insertable(cloneBean).executeRows(true) > 0L;

        // 指派角色
        this.assignRole(cloneBean, roleIdList);

        return ret;
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#listBy(java.util.Map)
     */
    @Override
    public List<EqUser> listBy(Map<String, Object> paraMap) {
        return this.buildQuery(null, paraMap).toList();
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#pageBy(int, int, java.util.Map)
     */
    @Override
    public PageResult<EqUser> pageBy(Page page, Map<String, Object> paraMap) {
        EasyPageResult<EqUser> pageList = this.buildQuery(page, paraMap).toPageResult(page.getPageNumber(), page.getPageSize());

        PageResult<EqUser> result = new PageResult<>();
        result.addAll(pageList.getData());
        result.setTotal(ConvertUtil.toInt(pageList.getTotal()));

        return result;
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#resetPassword(cn.hg.solon.youcan.system.entity.User, java.lang.String, java.lang.String, cn.hg.solon.youcan.system.entity.User)
     */
    @Tran
    @Override
    public void resetPassword(User bean, String oldPassword, String newPassword, User editor) {
        if (!PasswordUtil.validatePassword(bean.getSalt(), oldPassword, bean.getPassword())) {
            throw new ServiceException("旧密码不正确！");
        }

        this.resetPassword(bean, newPassword, editor);
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#resetPassword(cn.hg.solon.youcan.system.entity.User, java.lang.String, cn.hg.solon.youcan.system.entity.User)
     */
    @Tran
    @Override
    public void resetPassword(User bean, String password, User editor) {
        bean.setPassword(PasswordUtil.genSecretPassword(bean.getSalt(), password));
        bean.setEditedDatetime(DateUtil.now());

        EqUser cloneBean = BeanUtil.copyProperties(bean, EqUser.class);

        this.easyEntityQuery.updatable(cloneBean).executeRows();
    }

    /* (non-Javadoc)
     * @see cn.hg.solon.youcan.system.service.UserService#update(cn.hg.solon.youcan.system.entity.User)
     */
    @Override
    public boolean update(User bean) {
        if (!this.checkUnique(bean)) {
            throw new ServiceException("登录账号已经存在，请更换其它值！");
        }

        EqUser cloneBean = this.get(bean.getId());

        BeanUtil.copyProperties(bean, cloneBean, CopyOptions.of().setIgnoreNullValue(true));

        return this.easyEntityQuery.updatable(cloneBean).executeRows() > 0L;
    }
}
